using System;
using System.Threading.Tasks;
using MongoDB.Driver;
using Sustainalytics.ESGRatings.BusinessLogic.Computing.Exceptions;
using Sustainalytics.ESGRatings.DataContract;
using Sustainalytics.ESGRatings.DataLayer;

namespace Sustainalytics.ESGRatings.Computing.Service.Infrastructure
{
    public class ESGSetLoader
    {
        private readonly IMongoCollection<HistoricalDataSet> historicalCollection;
        private readonly IMongoCollection<DSCorporateData> corporateDataCollection;
        private readonly IMongoCollection<DSCompanyRawScores> rawScoresCollection;
        private readonly IMongoCollection<DSIndicatorTemplate> indicatorTemplatesCollection;
        private readonly IMongoCollection<DSWeightMatrix> weightMatrixCollection;
        private readonly IMongoCollection<DSReferenceUniverse> universesCollection;

        public ESGSetLoader(IMongoCollection<HistoricalDataSet> historicalCollection,
            IMongoCollection<DSCorporateData> corporateDataCollection,
            IMongoCollection<DSCompanyRawScores> indicatorDefaultScoresCollection,
            IMongoCollection<DSIndicatorTemplate> indicatorTemplatesCollection,
            IMongoCollection<DSWeightMatrix> weightMatrixCollection,
            IMongoCollection<DSReferenceUniverse> universesCollection)
        {
            this.universesCollection = universesCollection;
            this.weightMatrixCollection = weightMatrixCollection;
            this.indicatorTemplatesCollection = indicatorTemplatesCollection;
            this.rawScoresCollection = indicatorDefaultScoresCollection;
            this.corporateDataCollection = corporateDataCollection;
            this.historicalCollection = historicalCollection;
        }

        public async Task<ESGDataContainer> GetDataFromDatabase(Guid? setId)
        {
            HistoricalDataSet set;

            if (!setId.HasValue)
            {
                set =
                    (await historicalCollection.Find(dataSet => true)
                         .Sort(new SortDefinitionBuilder<HistoricalDataSet>().Descending(x => x.CreationDate))
                         .FirstOrDefaultAsync()
                         .ConfigureAwait(false));
            }
            else
            {
                set = (await historicalCollection
                        .Find(dataSet => dataSet.Id == setId.Value)
                        .FirstOrDefaultAsync()
                        .ConfigureAwait(false));
            }

            if (set == null)
            {
                throw new UnknownSetException(setId.GetValueOrDefault());
            }

            var companies = await corporateDataCollection
                           .Find(dataSet => dataSet.SetId == set.Id)
                           .Project(x => x.Instance)
                           .ToListAsync().ConfigureAwait(false);

            var indicatorTemplates = await indicatorTemplatesCollection
                       .Find(dataSet => dataSet.SetId == set.Id)
                       .Project(x => x.Instance)
                       .ToListAsync()
                       .ConfigureAwait(false);

            var defaultMatrixId = set.DefaultMatrixId;

            var indicatorDefaultScores = await rawScoresCollection.Find(dataSet => dataSet.SetId == set.Id).Project(x => x.Instance).ToListAsync().ConfigureAwait(false);

            var universes = await universesCollection
                      .Find(dataSet => dataSet.SetId == set.Id)
                      .Project(x => x.Instance)
                      .ToListAsync()
                      .ConfigureAwait(false);

            var matrices = await weightMatrixCollection
                      .Find(dataSet => dataSet.SetId == set.Id)
                      .Project(x => x.Instance)
                      .ToListAsync()
                      .ConfigureAwait(false);

            return new ESGDataContainer(set.Id, set.SetName, companies, indicatorDefaultScores, indicatorTemplates, matrices, universes, true, defaultMatrixId);

        }

    }
}